"""
@FileName：window_app.py\n
@Description：\n
@Author：锦沐Python\n
@Time：2024/8/19 12:02\n
"""
import csv
from datetime import datetime
import tkinter as tk

from ReLearning.data.file_tool import write_example_expression_data, read_example_expression_data, read_learn_data
from ReLearning.src.main_window_ui import MainWindowUi
from ReLearning.src.config import *


class WindowApp(MainWindowUi):
    def __init__(self):
        super().__init__()
        # 选择的模式
        self.all_modes = ENCODING_MODE[0]
        # 匹配模式追踪
        self.au_mode.trace("w", self.get_mode_select)
        for mode in self.select_modes_state:
            mode.trace("w", self.get_mode_select)

        # 常用匹配式列表
        self.common_expression_list = []
        self.pattern = None
        # 匹配详情列表
        self.match_detail_list = []

        # 表达输入追踪
        self.expression_entry_data.trace("w", self.expression_entry_data_change)
        self.replace_entry_data.trace("w", self.replace_match_data)
        # 菜单栏点击事件
        for button in self.menu_buttons:
            button.bind("<Button-1>", self.menu_button_clicked)

        # 常用表达式
        self.expression_title_list.bind("<ButtonRelease-1>", self.expression_title_click)
        self.document_list.bind("<ButtonRelease-1>", self.expression_document_click)
        self.rex_learn_list.bind("<ButtonRelease-1>", self.rex_learn_click)

        # 插入示例数据
        example_data = read_example_expression_data()
        self.example_types = set()
        for item in example_data:
            if item["type"] not in self.example_types:
                self.expression_title_list.insert("", "end", values=(item["type"],))
            self.example_types.add(item["type"])

        # 插入学习数据
        learn_data = read_learn_data()
        for item in learn_data:
            self.rex_learn_list.insert("", "end", values=(item["title"], item["description"], item["text"]))

    def get_mode_select(self, *args):
        """
        匹配模式配置
        """
        # 编码二选一
        self.all_modes = ENCODING_MODE[self.au_mode.get()]

        # 其他标志组合
        for index, state in enumerate(self.select_modes_state):
            if state.get() == 1:
                self.all_modes |= MODE[index]

        # print(self.all_modes)
        # 重新匹配高亮
        self.expression_entry_data_change()

    def menu_button_clicked(self, event):
        """
        菜单点击事件处理
        :param event:
        """
        # 获取触发事件的按钮的文本
        button_text = event.widget.cget('text')

        # 保存表达式
        if button_text == MEAU_ITEMS[0]:
            self.save_expression()
        # 匹配式测试
        elif button_text == MEAU_ITEMS[1]:
            self.hide_notebook()
        # 替换匹配项
        elif button_text == MEAU_ITEMS[2]:
            self.show_notebook()
            self.notebook.select(0)
        # 代码生成
        elif button_text == MEAU_ITEMS[3]:
            self.create_py_code()
        # 导出匹配项
        elif button_text == MEAU_ITEMS[4]:
            self.export_match_data()
        # 常用匹配式
        elif button_text == MEAU_ITEMS[5]:
            self.show_notebook()
            self.notebook.select(1)
        # 学习模式
        elif button_text == MEAU_ITEMS[6]:
            self.show_notebook()
            self.notebook.select(2)

    def expression_entry_data_change(self, *args):
        """
        正则表达式改变时，重新匹配测试
        :param args:
        """
        # 清空匹配信息列表
        self.match_detail_list.clear()
        # 获取表达式
        expression = self.expression_entry_data.get()
        # 获取测试文本
        all_content = self.data_text.get("1.0", tk.END)
        # 根据换行符将测试文本切割
        self.lines = all_content.split('\n')
        # 不开 多行模式 则只处理一行文本
        if re.MULTILINE not in self.all_modes:
            self.lines = [self.lines[0]]
        # 创建正则表达式对象
        try:
            self.pattern = re.compile(rf'{expression}', self.all_modes)
        except Exception as e:
            self.set_tips(msg="表达式不合法", m_type="info")
            return

        # 处理每一行
        for line_id, line in enumerate(self.lines):
            matches = self.pattern.finditer(line)
            for index, match in enumerate(matches):
                start = match.start()
                end = match.end()
                matched_text = match.group()  # 获取匹配到的字符串内容
                match_detail = {
                    "ID": index,
                    "interval": (start, end),
                    "matched_text": matched_text,
                    "line_id": line_id + 1
                }
                # 存入列表
                self.match_detail_list.append(match_detail)

        self.set_match_detail()
        self.data_text_highlight(color="red")

    def data_text_highlight(self, color):
        """
        高亮文本
        :param color: red | blue
        """
        # 去除之前的标签
        self.data_text.tag_remove(f"{color}_tag", "1.0", tk.END)
        # 打标签
        for item in self.match_detail_list:
            index_list = range(item["interval"][0], item["interval"][1])
            # 匹配位置区间逐个添加标签
            for index in index_list:
                self.data_text.tag_add(f"{color}_tag", f"{item['line_id']}.{index}")

        # 标注的文字显示颜色
        self.data_text.tag_config(f"{color}_tag", foreground=color)

    def expression_title_click(self, event):
        """
        获取点击事件
        :param event:
        """
        # 获取被点击的列表项
        item = self.expression_title_list.identify("item", event.x, event.y)
        if item:
            # 清空列表
            self.document_list.delete(*self.document_list.get_children())
            # 获取被点击项的文本
            values = self.expression_title_list.item(item, "values")
            # print(values)

            m_type = values[0]
            example_data = read_example_expression_data()
            self.filtered_data = list(filter(lambda x: x["type"] == m_type, example_data))

            for item in self.filtered_data:
                self.document_list.insert("", "end", values=(item["description"], item["expression"],))

    def expression_document_click(self, event):
        """
        查看表达式
        :param event:
        """
        # 获取被点击的列表项
        item = self.document_list.identify("item", event.x, event.y)
        if item:
            # 获取被点击项的文本
            values = self.document_list.item(item, "values")
            # print(values)
            tips = values[0]
            expression = values[1]
            self.set_tips(msg=tips, m_type="info")
            self.expression_entry_data.set(expression)

    def rex_learn_click(self, event):
        """
       学习表达式
       :param event:
       """
        # 获取被点击的列表项
        item = self.rex_learn_list.identify("item", event.x, event.y)
        if item:
            # 获取被点击项的文本
            values = self.rex_learn_list.item(item, "values")
            # print(values)

            title = values[0]
            description = values[1]
            test_text = values[2]

            self.data_text.delete("1.0", "end")
            self.tips_text.delete("1.0", "end")
            self.set_tips(msg=f"{title}:\n{description}", m_type="info")

            self.data_text.insert("end", test_text)

    def save_expression(self):
        """
        保存输入框内的表达式
        """
        expression = self.expression_entry_data.get()
        if expression:
            now_time = datetime.now().strftime("%Y-%m-%d %H%M%S")
            data = [
                {"type": "用户保存", "description": f"{now_time}", "expression": expression},
            ]
            write_example_expression_data(data)
            self.set_tips(msg=f"表达式: {expression} 保存成功", m_type="info")
        else:
            self.set_tips(msg=f"表达式为空", m_type="error")

    def create_py_code(self):
        """
        根据匹配式生成 py 代码，结果显示到提示框内
        """
        expression = self.expression_entry_data.get()
        flags = self.all_modes
        template = f"""
                    txt = "example_txt" 
                    pattern = re.compile(r'{expression}', {flags})
                    result = pattern.match(txt) 
                    """
        self.set_tips(msg=f"生成代码如下：\n{template}", m_type="info")

    def export_match_data(self):
        """
        将匹配的内容，导出到csv文件
        """
        try:
            if not self.match_detail_list:
                self.set_tips(msg=f"匹配详情为空", m_type="error")
                return

            now_time = datetime.now().strftime("%Y%m%d%H%M%S")
            with open(CSV_SAVE_PATH / f"{now_time}.csv", 'w', newline='', encoding='utf-8') as csvfile:
                writer = csv.DictWriter(csvfile, fieldnames=["ID", "interval", "matched_text", "line_id"])
                writer.writeheader()
                # 写入数据
                for row in self.match_detail_list:
                    writer.writerow(row)

            self.set_tips(msg=f"{now_time}.csv保存成功", m_type="info")
        except Exception as e:
            self.set_tips(msg=f"错误：{e}", m_type="error")

    def set_tips(self, msg, m_type):
        """
        给提示框填充内容
        """
        color = COLORS["info"]
        if m_type in COLORS.keys():
            color = COLORS[m_type]

        self.tips_text.insert("end", f"提示:{msg}\n\n", f"{color}_tag")
        self.tips_text.tag_config(f"{color}_tag", foreground=color)
        self.tips_text.see(tk.END)

    def set_match_detail(self):
        """
        给匹配详情填充内容
        """
        # 清空
        self.match_list.delete(*self.match_list.get_children())
        # 填充
        for item in self.match_detail_list:
            value = (item["ID"], (item["line_id"], item["interval"][0]), item["matched_text"])
            self.match_list.insert("", "end", values=value)

    def replace_match_data(self, *args):
        """
        将匹配的文本替换为用户输入的内容
        """
        replace_text = self.replace_entry_data.get()
        if not replace_text or self.pattern is None:
            self.set_tips(msg="替换文本为空请填写替换文本", m_type="error")
            return

        replace_counts = 0
        result_txt = ""
        for line in self.lines:
            result = self.pattern.subn(replace_text, line)
            replace_counts += result[1]
            result_txt += f"{result[0]}\n"

        self.set_tips(msg=f"总共替换次数:{replace_counts}", m_type="info")
        self.replace_result_txt.delete("1.0", "end")
        self.replace_result_txt.insert("end", result_txt)
